//
//  ViewController.m
//  KVO
//
//  Created by Hello Cai on 2019/3/31.
//  Copyright © 2019 Hello Cai. All rights reserved.
//

#import "ViewController.h"
#import "Person.h"
#import <objc/runtime.h>

@interface ViewController ()
@property(nonatomic, strong)Person *person1;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    Person *person1 = [[Person alloc] init];
    self.person1 = person1;
    [person1 setAge:5];
    NSLog(@"1.%@, %@", person1, object_getClass(person1));
    NSString *key = NSStringFromSelector(@selector(age));
    
    //注册观察者
    [person1 addObserver:self forKeyPath:key options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
    NSLog(@"2.%@, %@", person1, object_getClass(self.person1));
    
    //以下是手动触发KVO的例子：
    /*备注：automaticallyNotifiesObserversForKey用来决定是否要自动触发KVO，默认返回YES，即会自动触发KVO。
     我们可以在被观察者所在类中重写automaticallyNotifiesObserversForKey:，返回NO来避免自动触发KVO，这样注册观察者后，系统就不会动态创建子类
     */
    
    /*一般都是注册完观察者后(addObserver)，KVO自动触发，KVO流程：
        在给对象添加观察者时(addObserver)会动态创建子类，子类以NSKVONotifying_为前缀，由于内部修改了被观察者的isa指针的指向，被观察者变成子类的实例对象。子类会添加被观察属性的setter方法，相当于重写父类属性的setter方法。
        因此在注册完观察者后，我们使用的点语法实际调用的是子类重写的setter方法，KVO通知观察者属性值改变
        的关键在这个重写的setter方法中。以下我们简单模拟setter方法的关键语句，来手动触发KVO
     */

    //以下情况都是基于关闭自动触发KVO机制，即automaticallyNotifiesObserversForKey返回NO
    //情况一：只通过willChangeValueForKey和didChangeValueForKey两行就能触发KVO回调
//    [self situation1];
    
    //情况二：在willChangeValueForKey和didChangeValueForKey之间更改age，可以作为new值回调
//    [self situation2];
    
    //情况三：在didChangeValueForKey之后更改age，无法作为new值回调
//    [self situation3];
    
}

-(void)situation1{
    /*  打印
     --{
     kind = 1;
     new = 5;
     old = 5;
     }
     */
    NSString *key = NSStringFromSelector(@selector(age));
    [self.person1 willChangeValueForKey:key];
    [self.person1 didChangeValueForKey:key];
}


-(void)situation2{
    /*  打印
     --{
     kind = 1;
     new = 32;
     old = 5;
     }
     */
    NSString *key = NSStringFromSelector(@selector(age));
    [self.person1 willChangeValueForKey:key];
    [self.person1 setAge:32];
    [self.person1 didChangeValueForKey:key];
}

-(void)situation3{
    /*  打印
     --{
     kind = 1;
     new = 5;
     old = 5;
     }
     */
    NSString *key = NSStringFromSelector(@selector(age));
    [self.person1 willChangeValueForKey:key];
    [self.person1 didChangeValueForKey:key];
    [self.person1 setAge:32];
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    
    NSLog(@"--%@", change);
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
